package org.goldenport.g3.adapters

import javax.servlet.http.HttpServlet
import com.asamioffice.goldenport.servlet._
import com.asamioffice.goldenport.util.OptionUtil.lift
import org.goldenport.util.QSymbol
import org.goldenport.g3._
import org.goldenport.g3.messages._
import org.goldenport.g3.messages.event._
import org.goldenport.g3.events._
import org.goldenport.g3.events.event._

/**
 * @since   Mar. 31, 2011
 * @version Apr.  9, 2011
 * @author  ASAMI, Tomoharu
 */
class ServletAdapter(val driver: ServletDriver) extends G3Adapter {
  override def open_Adapter() {
    driver.open(context)
  }

  override def close_Adapter() {
    driver.close()
  }

  override protected def do_Action(content: AnyRef, parcel: G3Parcel, ctx: G3AgentContext): AnyRef = {
    content match {
      case cmd: G3Command => driver.execute(cmd, ctx)
    }
  }
}

object ServletAdapter {
  def create(servlet: HttpServlet): ServletAdapter = {
    new ServletAdapter(ServletDriver.create(servlet))
  }

  def create(servlet: Class[HttpServlet]): ServletAdapter = {
    new ServletAdapter(ServletDriver.create(servlet))
  }

  def create(servlet: String, ctx: G3Context): ServletAdapter = {
    new ServletAdapter(ServletDriver.create(servlet, ctx))
  }
}

class ServletDriver(val servlet: HttpServlet) extends G3Driver {
  protected def new_Agent(cmd: G3Command, ctx: G3AgentContext): ServletDriverAgent = new ServletDriverAgent(cmd.uri, servlet, ctx)
}

object ServletDriver {
  def create(servlet: HttpServlet) = {
    new ServletDriver(servlet)
  }

  def create(klass: Class[HttpServlet]) = {
    new ServletDriver(klass.newInstance)
  }

  def create(className: String, ctx: G3Context) = {
    new ServletDriver(ctx.newInstance(className))
  }
}

class ServletDriverAgent(uri: String, val servlet: HttpServlet, context: G3AgentContext) extends G3DriverAgent(uri, context) with UseRecord {
  val servletContext = new AgentServletContext()
  servlet.init(servletContext)
  println("ServletDriverAgent:" + servlet.getServletContext())

  def get(get: Get): G3Event = {
    val req = new AgentServletRequest("GET", get)
    val resp = new AgentServletResponse()
    servlet.service(req, resp)
    new Getted(uri, resp.content)
  }

  def put(put: Put): G3Event = {
    val req = new AgentServletRequest("PUT", put)
    val resp = new AgentServletResponse()
    servlet.service(req, resp)
    new Putted(uri, resp.content)
  }

  def post(post: Post): G3Event = {
    val req = new AgentServletRequest("POST", post)
    val resp = new AgentServletResponse()
    servlet.service(req, resp)
    new Posted(uri, resp.content)
  }

  def delete(delete: Delete): G3Event = {
    val req = new AgentServletRequest("DELETE", delete)
    val resp = new AgentServletResponse()
    servlet.service(req, resp)
    new Deleted(uri, resp.content)
  }

  def mkcol(mkcol: Mkcol): G3Event = {
    val req = new AgentServletRequest("MKCOL", mkcol)
    val resp = new AgentServletResponse()
    servlet.service(req, resp)
    new Mkcoled(uri, resp.content)
  }

  // 2011-04-02
  class AgentServletRequest(method: String, command: RestCommand) extends StubServletRequest {
    setMethod(method)
    pathInfo = command.uri match {
      case path if path.startsWith("/") => path
      case path => "/" + path
    }
    command.content match {
      case Some(s: String) => {
        setContent("text/plain", s)
      }
      case Some(r: Record) => {
        for (f <- r.fields) {
          parameters.put(f._1.name, f._2.toString)
        }
      }
      case None => {}
    }
  }

  class AgentServletResponse extends StubServletResponse {
    def content(): Option[AnyRef] = lift(getContent())
    def textContent(): Option[String] = lift(getTextContent())
    def binaryContent(): Option[Array[Byte]] = lift(getBinaryContent())
  }

  // 2011-04-09
  class AgentServletContext extends StubServletContext {
  }
}
